package com.jqq.api.utils;

import java.lang.reflect.Field;
import java.sql.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author 姬倩倩
 * @version 1.0
 * 封装dao层数据库代码
 * TODO：
 *    封装两个方法：简化非DQL，简化DQL
 */
public abstract class BaseDao {
    /**
     * 封装简化非DQL语句 返回值 固定为int
     * @param sql 带占位符的SQL语句
     * @param params 占位符的值 注意：传入占位符的值必须等于SQL？位置
     * @return 影响语句的行数
     */
    public int executeUpdate(String sql, Object... params) throws SQLException {
        //获取连接
        Connection connection = JdbcUtilsV2.getConnection();
        PreparedStatement preparedStatement = connection.prepareStatement(sql);
        //占位符赋值
        //可变参数可以当数组使用
        if(params != null && params.length != 0 ){
            for (int i = 1; i <= params.length; i++) {
                preparedStatement.setObject(i, params[i-1]);
            }
        }

        int rows = preparedStatement.executeUpdate();

        preparedStatement.close();

        //是否回收连接，需要考虑是不是事务
        //connection.close();//如果开启事务了 不要管连接即可 业务层处理
        if(connection.getAutoCommit())
        {
            JdbcUtilsV2.freeConnection();//没有开启事务,正常回收连接
        }

        return rows;
    }
    /**
     * DQL语句返回值-->是什么类型呢？-> List<T>
     * 并不是List<Map> map key和value自定义，不用先设定好
     *              map 没有数据校验机制
     *              map 不支持反射操作
     *  数据库 -> java的实体类
     *  table
     *      t_user
     *          id account password nickname
     *      java
     *          user
     *              id account password nickname
     *      表中一行 -> java类的一个对象 -> 多行 -> List<Java实体类> list;
     * <T> 声明一个泛型，不确定类型
     * 1.确定泛型 User.class T = User
     * 2.要使用反射技术属性赋值
     */
    /**
     *
     * @param clazz 要接值的实体类集合的模板对象
     * @param sql 查询语句 要求列名或者别名等于实体类的属性名
     * @param params 占位符的值 要和？位置对象传递
     * @param <T> 声明的结果的泛型
     * @return 查询的实体类集合
     * @throws Exception
     */
    public <T> List<T> executeQuery(Class<T> clazz,String sql, Object... params) throws Exception{
        //获取连接
        Connection connection = JdbcUtilsV2.getConnection();

        //创建preparedStatement并为占位符赋值
        PreparedStatement preparedStatement = connection.prepareStatement(sql);
        if(params != null && params.length != 0 ){
            for (int i = 1; i <= params.length; i++) {
                preparedStatement.setObject(i, params[i-1]);
            }
        }
        //发送SQL语句,得到结果集
        ResultSet resultSet = preparedStatement.executeQuery();
        //输出结果,并放到List中
        List<T> list = new ArrayList<>();

        //获取列信息对象
        //TODO:metaData装的当前结果集列的信息对象（可以根据下角标获取列的名称，获取列的数量）
        ResultSetMetaData metaData = resultSet.getMetaData();

        //有了它就可以水平遍历列了
        int columnCount = metaData.getColumnCount();

        while(resultSet.next()){
            T t = clazz.newInstance();//调用类的无参构造函数实例化对象

            //自动遍历列 【1，总列数】
            for (int i = 1; i <= columnCount; i++) {
                //对象的属性值
                Object value = resultSet.getObject(i);
                //获取指定列下角标的列的名称！ResultSetMetaData
                String propertyName = metaData.getColumnLabel(i);
                //反射，给对象的属性值赋值
                Field field = clazz.getDeclaredField(propertyName);
                field.setAccessible(true);
                /**
                 * 参数1：要赋值的对象 如果属性是静态 第一个参数可以为null
                 * 参数2：具体的属性值
                 */
                field.set(t, value);
            }
            list.add(t);
        }

        //8.关闭资源
        resultSet.close();
        preparedStatement.close();
        if(connection.getAutoCommit())
        {
            JdbcUtilsV2.freeConnection();//没有开启事务,正常回收连接
        }
        return list;
    }
}
